package ui;

import gragh.ENode;
import gragh.ListRedundancy;
import gragh.Redundancy;
import gragh.Way;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;
import javax.swing.JScrollPane;
import javax.swing.JList;
import javax.swing.JToggleButton;
import javax.swing.JTextPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.JTextArea;

import utility.Utility;

import database.attset.SetAttribute;
import database.fd.FDRedundancy;
import database.fd.FunctionalDependency;
import database.relation.Relation;
import database.relation.Table;
import javax.swing.JTextField;

import constraint.Constraint_v4;

public class OutputFrame extends JDialog {

    private ArrayList<Table> listTable;
    private ArrayList<Relation> listRelation;
    private ListRedundancy listRedundancy;
    private ArrayList<Way> listWay;
    private ArrayList<FDRedundancy> listFDRedundancy;
    private int selectedRundunction;
    private final int HEIGHT_LINE = 30;
    private final int RRLENGTH = 645;
    private ArrayList<SetAttribute> paths;
    
    private JPanel contentPane;
    private JList listPathRedundancy;
    private JTextArea textAreaDetail;
//    private JTextField textField;
    private JTextArea textAreaShowPaths;
    private JPanel panelOutputRedundancy;
    
    private JToggleButton btnViewAll;
    private JToggleButton btnViewNoignore;
    private JToggleButton btnViewIgnore;
    
    private JScrollPane scrollPaneListPathRedundancy;
    private JScrollPane scrollPaneDetail;
    private JScrollPane scrollPaneShowPaths;
    
    public OutputFrame(JFrame owner, 
                        ListRedundancy lsR,
                        ArrayList<Way> lsW,
                        ArrayList<FDRedundancy> lsFDR,
                        ArrayList<Table> lsTb,
                        ArrayList<Relation> lsRel) {
        super(owner, true);
        this.listRedundancy = lsR;
        this.listWay = lsW;
        this.listFDRedundancy = lsFDR;
        this.listTable = lsTb;
        this.listRelation = lsRel;
        

        setResizable(false);
        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        setTitle("Hiển thị kết quả");
        setBounds(100, 100, 800, 600);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);
        
        JTabbedPane tabbedPaneOutput = new JTabbedPane(JTabbedPane.TOP);
        tabbedPaneOutput.setBounds(10, 11, 774, 550);
        contentPane.add(tabbedPaneOutput);
        
        JPanel panelRedundancy = new JPanel();
        tabbedPaneOutput.addTab("Dư thừa", null, panelRedundancy, null);
        panelRedundancy.setLayout(null);
        
        JScrollPane scrollPaneOutputRedundancy = new JScrollPane();
        scrollPaneOutputRedundancy.setBounds(10, 32, 638, 202);
        panelRedundancy.add(scrollPaneOutputRedundancy);
        
        panelOutputRedundancy = new JPanel();
        scrollPaneOutputRedundancy.setViewportView(panelOutputRedundancy);
        panelOutputRedundancy.setLayout(null);
//        panelOutputRedundancy.setPreferredSize(new Dimension(4000, 5000));
//        panelOutputRedundancy.setPreferredSize(new Dimension(610, HEIGHT_LINE*showedRow));
        
        scrollPaneListPathRedundancy = new JScrollPane();
        scrollPaneListPathRedundancy.setBounds(10, 381, 190, 130);
        panelRedundancy.add(scrollPaneListPathRedundancy);
        
        listPathRedundancy = new JList();
//        listPathRedundancy.setBounds(10, 322, 199, 189);
//        panelRedundancy.add(listPathRedundancy);
        listPathRedundancy.addListSelectionListener(new ListSelectionListener() {
            
            @Override
            public void valueChanged(ListSelectionEvent e) {
                // TODO Auto-generated method stub
                JList jListPath = (JList) e.getSource();
                int indexPath = jListPath.getSelectedIndex();
                if (indexPath == -1) {
                    textAreaShowPaths.setText("");
                } else {
//                    String tmp = Utility.wayToString(listWay.get(paths.get(indexPath)), lsT, lsR);
                    StringBuffer sb = new StringBuffer();
                    SetAttribute path = paths.get(indexPath);
                    if (path.size() < 2) {
                        boolean res = false;
                        
                        // xu ly tham chieu de quy
                        RedundancyRow rr = (RedundancyRow) panelOutputRedundancy.getComponent(selectedRundunction);
                        if (rr.index < listRedundancy.size()) {
                            Redundancy r = listRedundancy.get(rr.index);
                            if (r.special == 1) {
                                res = true;
                                Constraint_v4 c4 = (Constraint_v4) r.node_1.constraint;
                                sb.append(Utility.joinToString(c4, listTable, listRelation));
                            }
                        }
                        
                        if (!res) {
                            sb.append("Không có phép kết.");
                        }
                    } else {
                        for (int i = 1; i < path.size(); i++) {
                            Integer w = path.get(i);
                            sb.append(Utility.wayToString(listWay.get(w), listTable, listRelation));
                            sb.append("\n");
                        }
                    }
                    
                    textAreaShowPaths.setText(sb.toString());
                }
                
                
//                System.out.println(jListPath.getSelectedIndex());
            }
        });
        scrollPaneListPathRedundancy.setViewportView(listPathRedundancy);
        
        btnViewAll = new JToggleButton("Tất cả");
        btnViewAll.setFont(new Font("Tahoma", Font.PLAIN, 9));
        btnViewAll.setToolTipText("xem tất cả dư thừa");
        btnViewAll.setBounds(659, 32, 100, 23);
        btnViewAll.setSelected(true);
        btnViewAll.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                
                if (!btnViewAll.isSelected()) {
                    btnViewAll.setSelected(true);
                } else {
                    btnViewNoignore.setSelected(false);
                    btnViewIgnore.setSelected(false);
                    
                    textAreaDetail.setText("");
                    listPathRedundancy.setListData(new Object[0]);
                    textAreaShowPaths.setText("");
                    
                    showAll();
                }
            }
        });
        panelRedundancy.add(btnViewAll);
        
        btnViewNoignore = new JToggleButton("Không chọn");
        btnViewNoignore.setFont(new Font("Tahoma", Font.PLAIN, 9));
        btnViewNoignore.setToolTipText("xem dư thừa không được chọn");
        btnViewNoignore.setBounds(659, 78, 100, 23);
        btnViewNoignore.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                
                if (!btnViewNoignore.isSelected()) {
                    btnViewNoignore.setSelected(true);
                } else {
                    btnViewAll.setSelected(false);
                    btnViewIgnore.setSelected(false);
                    
                    textAreaDetail.setText("");
                    listPathRedundancy.setListData(new Object[0]);
                    textAreaShowPaths.setText("");
                    
                    showNonIgnor();
                }
            }
        });
        panelRedundancy.add(btnViewNoignore);
        
        btnViewIgnore = new JToggleButton("Chọn");
        btnViewIgnore.setFont(new Font("Tahoma", Font.PLAIN, 9));
        btnViewIgnore.setToolTipText("xem dư thừa được chọn");
        btnViewIgnore.setBounds(659, 125, 100, 23);
        btnViewIgnore.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                
                if (!btnViewIgnore.isSelected()) {
                    btnViewIgnore.setSelected(true);
                } else {
                    btnViewAll.setSelected(false);
                    btnViewNoignore.setSelected(false);
                    
                    textAreaDetail.setText("");
                    listPathRedundancy.setListData(new Object[0]);
                    textAreaShowPaths.setText("");
                    
                    showIgnor();
                }
            }
        });
        panelRedundancy.add(btnViewIgnore);
        
        scrollPaneDetail = new JScrollPane();
        scrollPaneDetail.setBounds(87, 245, 561, 100);
        panelRedundancy.add(scrollPaneDetail);
        
        textAreaDetail = new JTextArea();
        textAreaDetail.setEditable(false);
        scrollPaneDetail.setViewportView(textAreaDetail);
        
        scrollPaneShowPaths = new JScrollPane();
        scrollPaneShowPaths.setBounds(219, 381, 429, 130);
        panelRedundancy.add(scrollPaneShowPaths);
        
        textAreaShowPaths = new JTextArea();
        textAreaShowPaths.setEditable(false);
        scrollPaneShowPaths.setViewportView(textAreaShowPaths);
        
        JLabel lblListRedundancies = new JLabel("Danh sách các dư thừa dữ liệu");
        lblListRedundancies.setBounds(10, 7, 178, 18);
        panelRedundancy.add(lblListRedundancies);
        
        JLabel lblIgnor = new JLabel("Bỏ qua");
        lblIgnor.setBounds(569, 7, 73, 18);
        panelRedundancy.add(lblIgnor);
        
        JLabel lblDetail = new JLabel("Chi tiết :");
        lblDetail.setFont(new Font("Tahoma", Font.BOLD, 14));
        lblDetail.setBounds(10, 245, 67, 23);
        panelRedundancy.add(lblDetail);
        
        JLabel lblTableInfo = new JLabel("Thông tin quan hệ");
        lblTableInfo.setBounds(10, 352, 121, 18);
        panelRedundancy.add(lblTableInfo);
        
        JLabel lblJoinInfo = new JLabel("Thông tin phép kết");
        lblJoinInfo.setBounds(219, 352, 121, 18);
        panelRedundancy.add(lblJoinInfo);
        
          // hien thi cac du thua
        showAll();
        
        JPanel panelNormalizeForm = new JPanel();
        tabbedPaneOutput.addTab("Dạng chuẩn", null, panelNormalizeForm, null);
        panelNormalizeForm.setLayout(null);
        
        tabbedPaneOutput.setSelectedIndex(0);
        
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setBounds(10, 11, 749, 500);
        panelNormalizeForm.add(scrollPane);
        
        JTextArea textArea = new JTextArea();
        scrollPane.setViewportView(textArea);
        
        String tmp = "";
        int minNF = 5;
        for(int n = 0; n < lsRel.size(); n++) {
            Relation r = lsRel.get(n);
            Table t = lsTb.get(n);
            
            tmp += (n+1) + ". ";
            
            tmp += t.getTableName() + "(";
            
            for(int m = 0; m < t.getListColumn().length; m++) {
                tmp += (m == t.getListColumn().length - 1 ? t.getListColumn()[m] + ")" : t.getListColumn()[m] + " ,");
            }
            
            if(r.is2NormalForm()) {
                if(r.is3NormalForm()) {
                    if(r.isBCNormalForm()) {
                        tmp += " đạt chuẩn BCNF.";
                        if(minNF > 4) {
                            minNF = 4;
                        }
                    } else {
                        tmp += " đạt chuẩn 3NF.";
                        if(minNF > 3) {
                            minNF = 3;
                        }
                    }
                } else {
                    tmp += " đạt chuẩn 2NF.";
                    if(minNF > 2) {
                        minNF = 2;
                    }
                }
            } else {
                tmp += "đạt chuẩn 1NF.";
                if(minNF > 1) {
                    minNF = 1;
                }
            }
            
            tmp += "\nThông tin chi tiết:\n";
            tmp += Utility.getAllDetailTable(listTable.get(n), listRelation.get(n), listTable, listRelation);
            tmp += "\n\n";
        }
        
        tmp += "-------------------------------------------------\n";
        
        tmp += "Cơ sở dữ liệu này đạt chuẩn ";
        
        switch (minNF){
        case 1:
                tmp += "1NF.";
                break;
        case 2:
                tmp += "2NF.";
                break;
        case 3:
                tmp += "3NF.";
                break;
        case 4:
                tmp += "BCNF.";
                break;
        }
        
        textArea.setText(tmp);
        
    }
    
    private void showAll() {
        panelOutputRedundancy.removeAll();
        System.gc();
        
        int n = listRedundancy.size() + listFDRedundancy.size();
        int i = 0;
        for (i = 0; i < listRedundancy.size(); i++) {
            Redundancy r = listRedundancy.get(i);
            RedundancyRow rr = new RedundancyRow();
            String strShow = (i+1) + ". " + title_R(r);
            
            rr.index = i;
            rr.chckbxIgnore.setSelected(!r.show);
            rr.chckbxIgnore.addActionListener(new MyActionListener());
            rr.lbRedundancy.setText(strShow);
            rr.setBounds(0, i*HEIGHT_LINE, RRLENGTH, HEIGHT_LINE);
            
            rr.indexShowing = i;
            rr.addMouseListener(new MyMouseListener());
            panelOutputRedundancy.add(rr);
        }
        int j = 0;
        for (j = 0; j < listFDRedundancy.size(); j++) {
            FDRedundancy fdr = listFDRedundancy.get(j);
            RedundancyRow fdrr = new RedundancyRow();
            String strShow = (i+j+1) + ". " + title_FDR(fdr);
            
            fdrr.index = i+j;
            fdrr.chckbxIgnore.setSelected(!fdr.show);
            fdrr.chckbxIgnore.addActionListener(new MyActionListener());
            fdrr.lbRedundancy.setText(strShow);
            fdrr.setBounds(00, (i+j)*HEIGHT_LINE, RRLENGTH, HEIGHT_LINE);
            
            fdrr.indexShowing = i + j;
            fdrr.addMouseListener(new MyMouseListener());
            panelOutputRedundancy.add(fdrr);
        }
        
        panelOutputRedundancy.setPreferredSize(new Dimension(600, n*HEIGHT_LINE));
        panelOutputRedundancy.validate();
        panelOutputRedundancy.repaint();
        
        if (n > 0) {
            selectedRundunction = 0;
            ((RedundancyRow)panelOutputRedundancy.getComponent(0)).setSelected();
            selectRedundancy(0);
        }
    }
    
    private void showNonIgnor() {
        panelOutputRedundancy.removeAll();
        System.gc();
        
        int n = 0;
        int i = 0;
        for (i = 0; i < listRedundancy.size(); i++) {
            Redundancy r = listRedundancy.get(i);
            if (r.show) {
                RedundancyRow rr = new RedundancyRow();
                String strShow = (i+1) + ". " + title_R(r);
                
                rr.index = i;
                rr.chckbxIgnore.setSelected(!r.show);
                rr.chckbxIgnore.addActionListener(new MyActionListener());
                rr.lbRedundancy.setText(strShow);
                rr.setBounds(0, n*HEIGHT_LINE, RRLENGTH, HEIGHT_LINE);
                
                rr.indexShowing = n;
                rr.addMouseListener(new MyMouseListener());
                panelOutputRedundancy.add(rr);
                
                //cap nhat n
                n++;
            }
        }
        int j = 0;
        for (j = 0; j < listFDRedundancy.size(); j++) {
            FDRedundancy fdr = listFDRedundancy.get(j);
            if (fdr.show) {
                RedundancyRow fdrr = new RedundancyRow();
                String strShow = (i+j+1) + ". " + title_FDR(fdr);
                
                fdrr.index = i+j;
                fdrr.chckbxIgnore.setSelected(!fdr.show);
                fdrr.chckbxIgnore.addActionListener(new MyActionListener());
                fdrr.lbRedundancy.setText(strShow);
                fdrr.setBounds(0, n*HEIGHT_LINE, RRLENGTH, HEIGHT_LINE);
                
                fdrr.indexShowing = n;
                fdrr.addMouseListener(new MyMouseListener());
                panelOutputRedundancy.add(fdrr);
                
                //cap nhat n
                n++;
            }
        }
        
        panelOutputRedundancy.setPreferredSize(new Dimension(600, n*HEIGHT_LINE));
        panelOutputRedundancy.validate();
        panelOutputRedundancy.repaint();
        
        if (n > 0) {
            selectedRundunction = 0;
            ((RedundancyRow)panelOutputRedundancy.getComponent(0)).setSelected();
            int irr = ((RedundancyRow)panelOutputRedundancy.getComponent(0)).index;
            selectRedundancy(irr);
        }
    }
    
    private void showIgnor() {
        panelOutputRedundancy.removeAll();
        System.gc();
        
        int n = 0;
        int i = 0;
        for (i = 0; i < listRedundancy.size(); i++) {
            Redundancy r = listRedundancy.get(i);
            if (!r.show) {
                RedundancyRow rr = new RedundancyRow();
                String strShow = (i+1) + ". " + title_R(r);
                
                rr.index = i;
                rr.chckbxIgnore.setSelected(!r.show);
                rr.chckbxIgnore.addActionListener(new MyActionListener());
                rr.lbRedundancy.setText(strShow);
                rr.setBounds(0, n*HEIGHT_LINE, RRLENGTH, HEIGHT_LINE);
                
                rr.indexShowing = n;
                rr.addMouseListener(new MyMouseListener());
                panelOutputRedundancy.add(rr);
                
                //cap nhat n
                n++;
            }
        }
        int j = 0;
        for (j = 0; j < listFDRedundancy.size(); j++) {
            FDRedundancy fdr = listFDRedundancy.get(j);
            if (!fdr.show) {
                RedundancyRow fdrr = new RedundancyRow();
                String strShow = (i+j+1) + ". " + title_FDR(fdr);
                
                fdrr.index = i+j;
                fdrr.chckbxIgnore.setSelected(!fdr.show);
                fdrr.chckbxIgnore.addActionListener(new MyActionListener());
                fdrr.lbRedundancy.setText(strShow);
                fdrr.setBounds(0, n*HEIGHT_LINE, RRLENGTH, HEIGHT_LINE);
                
                fdrr.indexShowing = n;
                fdrr.addMouseListener(new MyMouseListener());
                panelOutputRedundancy.add(fdrr);
                
                //cap nhat n
                n++;
            }
        }
        
        panelOutputRedundancy.setPreferredSize(new Dimension(600, n*HEIGHT_LINE));
        panelOutputRedundancy.validate();
        panelOutputRedundancy.repaint();
        
        if (n > 0) {
            selectedRundunction = 0;
            ((RedundancyRow)panelOutputRedundancy.getComponent(0)).setSelected();
            int irr = ((RedundancyRow)panelOutputRedundancy.getComponent(0)).index;
            selectRedundancy(irr);
        }
    }
    
    public String title_R(Redundancy r) {
        String title = "";
        
        title = "Dư thừa do dẫn xuất: ";
//        title += Utility.getEvidence(r);
        title += Utility.getTitleR(r);
        
        return title;
    }
    
    public String title_FDR(FDRedundancy fdr) {
        String title = "";
        String left = "";
        String right = "";
        
        title = "Dư thừa do phụ thuộc hàm: ";
        
        FunctionalDependency fd = fdr.lsFd.get(0);
        left = "(";
        for (int i = 0; i < fd.left.size(); i++) {
            Integer att = fd.left.get(i);
            if (i > 0) {
                left += ", ";
            }
            left += Utility.getAttributeInTable(att, listTable,
                    listRelation);
        }
        left += ")";

        right = "(";
        for (int i = 0; i < fd.right.size(); i++) {
            Integer att = fd.right.get(i);
            if (i > 0) {
                right += ", ";
            }
            right += Utility.getAttributeInTable(att, listTable,
                    listRelation);
        }
        right += ")";
        title += left + " -> " + right;
        
        return title;
    }
    
    private void selectRedundancy(int indexR) {
        String[] listPath;
        Redundancy r = null;
        paths = new ArrayList<SetAttribute>();
        
        if (indexR < listRedundancy.size()) {
            r = listRedundancy.get(indexR);
            int n = 0;
            for (ArrayList<SetAttribute> arrSet : r.paths) {
                n += arrSet.size();
            }
            listPath = new String[n];
            
            int i = 0;
            for (ArrayList<SetAttribute> arrPath : r.paths) {
                for (SetAttribute path : arrPath) {
                    // listPath[i] = set.toString();
                    listPath[i] = (i+1) + ". " + Utility.getListTableNameFromListPathIndex(path, listWay, listRelation);
                    paths.add(path);
                    i++;
                }
            }

            listPathRedundancy.setListData(listPath);
            if (listPath.length > 0) {
                listPathRedundancy.setSelectedIndex(0);
            }
        } else {
            // ko hien thi path
            listPath = new String[0];
            listPathRedundancy.setListData(listPath);
        }

        // cap nhat khung detail o giua
        if (indexR < listRedundancy.size()) {
            String tmp = Utility.strShowRedundancy(r, listTable,
                    listRelation);
            tmp += "-------\nCác bảng liên quan:\n";
            tmp += Utility.getAllTables(r, listTable, listRelation);
            tmp += "-------\nCăn cứ:\n";
            tmp += Utility.getEvidence(r);
            textAreaDetail.setText(tmp);
        } else {
            FDRedundancy fdr = listFDRedundancy.get(indexR - listRedundancy.size());
            String left = "";
            String right = "";
            StringBuffer sb = new StringBuffer();

            sb.append("Bảng " + fdr.relation);
            sb.append(" (" + fdr.form + ") ");
            sb.append("có các thuộc tính dư thừa:");

            int k = 1;
            for (FunctionalDependency fd : fdr.lsFd) {
                left = "(";
                for (int i = 0; i < fd.left.size(); i++) {
                    Integer att = fd.left.get(i);
                    if (i > 0) {
                        left += ", ";
                    }
                    left += Utility.getAttributeInTable(att, listTable,
                            listRelation);
                }
                left += ")";

                right = "(";
                for (int i = 0; i < fd.right.size(); i++) {
                    Integer att = fd.right.get(i);
                    if (i > 0) {
                        right += ", ";
                    }
                    right += Utility.getAttributeInTable(att, listTable,
                            listRelation);
                }
                right += ")";

                sb.append("\n" + k + ". Những thuộc tính ");
                sb.append(right + " ");
                sb.append("bị dư thừa do phụ thuộc hàm ");
                sb.append(left + "->" + right);
                
                sb.append("\n-------\nThông tin bảng:\n");
                int indexT = Utility.getIndexOfTable(fdr.relation, listTable);
                sb.append(Utility.getAllTable(listTable.get(indexT)));
                k++;
            }

            textAreaDetail.setText(sb.toString());
        }
    }    
    
    public class MyMouseListener extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {
            RedundancyRow rr = (RedundancyRow) e.getSource();
            
            // TODO
//            int indexShowedR = panelOutputRedundancy.in
            if (!rr.isSelected) {
                int preSeleted = selectedRundunction;
                RedundancyRow preRR = (RedundancyRow) panelOutputRedundancy.getComponent(preSeleted);
                
                preRR.setNonSelected();
                rr.setSelected();
                
                selectedRundunction = rr.indexShowing;
                
                selectRedundancy(rr.index);
            }
        }
    }
    
    public class MyActionListener implements ActionListener {
        
        @Override
        public void actionPerformed(ActionEvent e) {
            JCheckBox jChkBox = (JCheckBox) e.getSource();
            RedundancyRow rr = (RedundancyRow) jChkBox.getParent();

            if (rr.index < listRedundancy.size()) {
                listRedundancy.get(rr.index).show = !jChkBox.isSelected();
            } else {
                listFDRedundancy.get(rr.index - listRedundancy.size()).show = !jChkBox.isSelected();
            }
        }
    }
}
